﻿using Core.IServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Core.Messages;
using Core.Dtos;
using Core.Domain;
using Core.Queries;
using Core.IRepository;
using Library.Cache;
using Library.Logging;
using AutoMapper;
using Core.Aspects;

namespace Services
{
    public sealed class GenericWriterService<TId, TEntity, TDto, TQuery> : BaseService, IGenericWriterService<TId, TEntity, TDto, TQuery>
        where TDto : BaseDto<TId>
        where TEntity : IBaseEntity<TId>
        where TQuery : Query<TEntity>
    {
        public IUnitOfWork unitOfWork {get;set;}
        public IRepository<TId, TEntity> repository {get;set;}

        public void Initialize(IUnitOfWork unitOfWork, IRepository<TId, TEntity> repository) 
        {
            this.unitOfWork = unitOfWork;
            this.repository = repository;
        }

        public GenericWriterService()
        {
        }

        public Response<TId> Add(Request<TDto> request)
        {
            return Add(request.Value, entity => entity);
        }

        [HandleServiceError]
        public Response<TId> Add(TDto dto, Func<TEntity, TEntity> setEntity)
        {
            Response<TId> response = new Response<TId>();

            TEntity entity = Mapper.Map<TDto, TEntity>(dto);
            entity = setEntity(entity);

            if (entity.Validate())
            {
                repository.Add(entity);
                unitOfWork.Commit();
                response.Value = entity.Id;
                response.Success = true;
            }
            else
            {
                response.Success = false;
                response.BrokenRules = entity.BrokenRules;
            }

            return response;
        }

        public Response Edit(TId id, Request<TDto> request)
        {
            return Edit(id, request.Value, entity => entity);
        }
       
        [HandleServiceError]
        public Response Edit(TId id, TDto dto, Func<TEntity, TEntity> setEntity)
        {
            Response response = new Response();

            TEntity entity = repository.FindBy(id);
            Mapper.Map<TDto, TEntity>(dto, entity);
            entity = setEntity(entity);

            if (entity.Validate())
            {
                repository.Edit(entity);
                unitOfWork.Commit();
                response.Success = true;
            }
            else
            {
                response.Success = false;
                response.BrokenRules = entity.BrokenRules;
            }

            return response;
        }
       
        [HandleServiceError]
        public Response Delete(TId id)
        {
            Response response = new Response();
            TEntity entity = repository.FindBy(id);

            if (entity != null)
            {
                repository.Delete(entity);
                unitOfWork.Commit();
            }
            response.Success = true;
            
            return response;
        }
    }
}
